//
// Created by HP on 2022/1/19.
//

#ifndef VULKAN_TUTORIAL_LVE_MODEL_H
#define VULKAN_TUTORIAL_LVE_MODEL_H

#include "lve_device.h"

// libs
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/glm.hpp>

// std
#include <memory>

namespace lve {
    // 用于将通过 CPU 读入的顶点数据传输到 GPU 中
    class LveModel {
    public:

        struct Vertex {
            glm::vec3 position{};
            glm::vec3 color{};
            glm::vec3 normal{};
            glm::vec2 uv{};

            static std::vector<VkVertexInputBindingDescription> getBindDescription();
            static std::vector<VkVertexInputAttributeDescription> getAttributeDescriptions();
            bool operator==(const Vertex &other) const {
                return position == other.position &&
                       color    == other.color    &&
                       uv       == other.uv;
            }
        };

        struct Builder {
            std::vector<Vertex> vertices{};
            std::vector<uint32_t> indices{};

            void loadModel(const std::string& filepath);
        };

        LveModel(LveDevice &device, const Builder &builder);
        ~LveModel();

        LveModel(const LveModel&) = delete;
        LveModel& operator=(const LveModel&) = delete;

        static std::unique_ptr<LveModel> createModelFromFile(
            LveDevice &device, const std::string &filepath);

        void bind(VkCommandBuffer commandBuffer);
        void draw(VkCommandBuffer commandBuffer) const;
    private:
        void createVertexBuffers(const std::vector<Vertex> &vertices);
        void createIndexBuffers(const std::vector<uint32_t> &indices);

        LveDevice& lveDevice;
        // 在 vulkan 中, buffer 和 它所分配到的内存是两个单独的对象
        VkBuffer vertexBuffer{};
        VkDeviceMemory vertexBufferMemory{};
        uint32_t vertexCount{};

        bool hasIndexBuffer = false;
        VkBuffer indexBuffer{};
        VkDeviceMemory indexBufferMemory{};
        uint32_t indexCount{};
    };
}

#endif //VULKAN_TUTORIAL_LVE_MODEL_H
